import Event from "../../event/index"
import { isClickOnSprite } from '../../utils/index'
import { getUuid, extendClass } from "../../utils/index"
import { getCtx } from '../../../ctx/index'

const EventMap = new WeakMap()
/**
 * 基础渲染类
 */
export default class Base {
  constructor() {
    /**
     * 组件唯一id
     */
    this.id = getUuid()
    /**
     * 子组件数组
     */
    this.children = []
    this.width = 0
    this.height = 0
    this.top = 0
    this.left = 0
    this.x = 0
    this.y = 0
    this.visible = true
    this.zIndex = 0
    this.parnet = null
    extendClass(this)
    this.onLoad()
  }
  onLoad () {}
  $getGrivate (){
    return EventMap.get(this)
  }
  _executeEvent (list, type, ...ages) {
    let isStop = false
    const stop = () => {
      isStop = true
    }
    list.reverse()
    for (let i = 0; i < list.length; i++) {
      if (isStop) {
        break
      }
      ages.splice(0, 1, {
        ...ages[0],
        stop
      })
      const current = list[i]
      current._exeEventListen(type, ...ages)
    }
  }
  _exeEventListen (type, ...ages) {
    const temp = this.$getGrivate() || {}
    if (temp[type]) {
      const { changedTouches } = ages[0]
      const param = changedTouches[0]
      if (!isClickOnSprite(this, param.pageX, param.pageY)) {
        return
      }
      temp[type].forEach(fn => fn(...ages))
    }
  }
  _eventCaptur (e) {
    const pathList = [this]
    let currentItem = this
    while (currentItem.children.length > 0) {
      const list = []
      currentItem.children.forEach(item => {
        const param = e.changedTouches[0]
        if (item.visible && isClickOnSprite(item, param.pageX, param.pageY)) {
          list.push(item)
        }
      })
      const sortList = list.sort((a, b) => a.zIndex - b.zIndex)
      const lastItem = sortList[sortList.length - 1]
      if (lastItem) {
        currentItem = lastItem
        pathList.push(lastItem)
      } else {
        break
      }
    }
    return pathList
  }
  _listen(type, ...e) {
    const temp = this.$getGrivate() || {}
    if (temp[type]) {
      const { changedTouches } = e[0]
      const param = changedTouches[0]
      if (!isClickOnSprite(this, param.pageX, param.pageY)) {
        return
      }
      temp[type].forEach(fn => fn(...e))
    }
    if (this.children) {
      this.children.forEach(child => {
        child._listen(type, ...e)
      })
    }
  }
  /**
   * 监听自定义事件
   * @param {String} type 
   * @param  {...any} e 
   */
  _listenCustomEvent (type, ...e) {
    const temp = this.$getGrivate() || {}
    if (temp[type]) {
      temp[type].forEach(fn => fn(...e))
    }
    if (this.children) {
      this.children.forEach(child => {
        child._listenCustomEvent(type, ...e)
      })
    }
  }
  /**
   * 添加事件
   */
  addEvent(type, fn) {
    const temp = this.$getGrivate() || {}
    if (temp[type]) {
      temp[type].push(fn)
    } else {
      temp[type] = [fn]
    }
    EventMap.set(this, temp)
  }
  /**
   * 移除事件
   */
  removeEvent (type, fn) {
    if (!type) { 
      return false
    }
    const temp = this.$getGrivate() || {}
    if (temp[type]) {
      if (!fn) {
        temp[type] = []
      } else {
        const index = temp[type].findIndex(f => f === fn)
        temp[type].slice(index, 1)
      }
    }
    EventMap.set(this, temp)
    return true
  }
  /**
   * 添加组子件
   */
  appendChild(...ags) {
    ags.forEach(item => {
      if (this.children.find(e => e.id === item.id)) {
        return
      }
      if (item) {
        item.parnet = this
        this.children.push(item)
      }
    })
  }
  /**
 * 移除子组件
 */
  removeChild (child) {
    this.children = this.children.filter(item => item.id !== child.id)
  }
  /**
   * 排序子组件更新逻辑
   */
  _sortChildren () {
    const renderList = this.children.reduce((list, item) => {
      if (!item) {
        return list
      }
      list.push({
        zIndex: item.zIndex,
        render: item.render.bind(item),
        update: item.update.bind(item),
        renderChildren: item.renderChildren.bind(item),
        updateChildren: item.updateChildren.bind(item),
      })
      return list
    }, [])
    renderList.sort((a, b) => a.zIndex - b.zIndex)
    return renderList
  }
  /**
   * 更新组组件
   */
  updateChildren () {
    this._sortChildren().forEach(child => {
      child.update()
      child.updateChildren()
    })
  }
  /**
   * 渲染子组件
   */
  renderChildren (ctx = getCtx()) {
    this._sortChildren().forEach(child => {
      child.render(ctx)
      child.renderChildren(ctx)
    })
  }
}